package org.springframework.beans.factory.context.annotation;

import org.springframework.beans.factory.anno.Lazy;
import org.springframework.beans.factory.anno.Role;
import org.springframework.beans.factory.anno.Scope;
import org.springframework.beans.factory.config.*;
import org.springframework.beans.factory.support.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.util.ConfigurationClassUtils;
import org.springframework.core.type.AnnotationMetadata;

import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

/**
 * @author:刘仁有
 * @desc:
 * @email:953506233@qq.com
 * @data:2019/12/14
 */
public abstract class AnnotationConfigUtils {

    public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME =
            "org.springframework.context.annotation.internalConfigurationAnnotationProcessor";

    public static final String AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME =
            "org.springframework.context.annotation.internalAutowiredAnnotationProcessor";

    public static final String COMMON_ANNOTATION_PROCESSOR_BEAN_NAME =
            "org.springframework.context.annotation.internalCommonAnnotationProcessor";


    public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
        registerAnnotationConfigProcessors(registry, null);
    }

    public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
            BeanDefinitionRegistry registry, Object source) {

        Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
        //ConfigurationClassPostProcessor这个bean工厂后置处理器主要做解析配置config的功能
        if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
            def.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
            beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
        }
        //AutowiredAnnotationBeanPostProcessor主要做推断构造器，缓存@Autowired属性 给DI使用，
        if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
            def.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
            beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
        }
        //这个CommonAnnotationBeanPostProcessor暂时未开发
        //spring这个的作用是缓存@Resource的属性 给DI使用
        if (!registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
            def.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
            beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

        return beanDefs;
    }

    private static BeanDefinitionHolder registerPostProcessor(BeanDefinitionRegistry registry, RootBeanDefinition def, String beanName) {
        registry.registerBeanDefinition(beanName,def);
        return new BeanDefinitionHolder(beanName,def);
    }
    //处理 @Role @Scope @Lazy
    public static void processCommonDefinitionAnnotations(AnnotatedGenericBeanDefinition abd) {
        AnnotationMetadata metadata = abd.getMetadata();

        if(metadata.hasAnnotation(Role.class)){
            Map<String, Object> annoMap =  metadata.getAnnotationAttributes(Role.class);
            if(null!=annoMap&&annoMap.size()>0&&annoMap.containsKey(ConfigurationClassUtils.CONFIGURATION_VALUE)){
                Object value = annoMap.get(ConfigurationClassUtils.CONFIGURATION_VALUE);
                abd.setRole((Integer) value);
            }
        }

        if(metadata.hasAnnotation(Scope.class)){
            Map<String, Object> annoMap =  metadata.getAnnotationAttributes(Scope.class);
            if(null!=annoMap&&annoMap.size()>0&&annoMap.containsKey(ConfigurationClassUtils.CONFIGURATION_VALUE)){
                Object value = annoMap.get(ConfigurationClassUtils.CONFIGURATION_VALUE);
                abd.setScope((String) value);
            }
        }

        if(metadata.hasAnnotation(Lazy.class)){
            Map<String, Object> annoMap =  metadata.getAnnotationAttributes(Lazy.class);
            if(null!=annoMap&&annoMap.size()>0&&annoMap.containsKey(ConfigurationClassUtils.CONFIGURATION_VALUE)){
                Object value = annoMap.get(ConfigurationClassUtils.CONFIGURATION_VALUE);
                abd.setLazyInit((Boolean) value);
            }
        }
    }
}
